package ru.JDiskCatalog.ui;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.ArrayList;

import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.ExpandVetoException;
import javax.swing.tree.TreeSelectionModel;

import ru.JDiskCatalog.entities.DirectoryInfo;
import ru.JDiskCatalog.entities.FileInfo;
import ru.JDiskCatalog.entities.MediaInfo;
import ru.JDiskCatalog.util.DateValueCellRenderer;
import ru.JDiskCatalog.util.LongValueCellRenderer;
import ru.JDiskCatalog.util.SqlUtil;

public class CatalogBrowser extends JSplitPane {
	private JTable ctlFilesList;
	private JScrollPane ctlTreeScroll;
	private JTree ctlDirectoryTree;
	private JScrollPane ctlListScroll;
	private Connection m_objConnection;	
    private String connectionString="";
    
	public CatalogBrowser(String strDBPath)
	{
		super();
		
		connectionString="jdbc:derby:"+strDBPath;
		
		InitGUI();
		FillCatalogData();				
	}
	
	public void Cleanup()
	{
		JTabbedPane ctlTabPane=(JTabbedPane)getParent();
		Component[] arrComponents=ctlTabPane.getComponents();
		for(Component objComponent : arrComponents)
			if(objComponent instanceof CatalogSearch)
			{
				CatalogSearch objSearch=(CatalogSearch)objComponent;
				if(objSearch.getConnection()==m_objConnection)
					ctlTabPane.remove(objSearch);
			}
		
        //close Connection
        if (m_objConnection != null)                
            try 
            {
                	m_objConnection.close();
                	m_objConnection = null;	
            } 
            catch (SQLException sqle) 
            {
            	SqlUtil.ReportSQLException(sqle);
            }
	}

    public Connection getDBConnection()
    {
    	if(m_objConnection==null)
    	{
	    	try
	    	{	
	    		m_objConnection=DriverManager.getConnection(connectionString);	    		
	    	}
	    	catch(SQLException sqle)
	    	{
            	SqlUtil.ReportSQLException(sqle);
	    	}
    	}
    	
    	return m_objConnection;
    }
    
	private void InitGUI()
	{
		try		
		{
			{
				ctlTreeScroll=new JScrollPane();
				add(ctlTreeScroll, JSplitPane.LEFT);
			}
			{
				ctlListScroll = new JScrollPane();
				add(ctlListScroll, JSplitPane.RIGHT);
			}
			
			setDividerLocation(200);
		}
		catch (Exception e) 
		{
			e.printStackTrace();
		}		
	}
	
	private void FillCatalogData()
	{
		DefaultMutableTreeNode top =new DefaultMutableTreeNode("Media");	
		Statement s=null;
		ResultSet rs=null;
		PreparedStatement ps=null;
		ResultSet rsRoot=null;
		
		try
		{
			s=getDBConnection().createStatement();
			rs=s.executeQuery("SELECT MEDIA_ID,\"NAME\",\"PATH\" FROM MEDIA");
			
			while(rs.next())
			{
				int RootDirectoryID=0;

				ps=getDBConnection().prepareStatement(
						"SELECT D1.DIRECTORY_ID,D1.PARENT_ID,D1.NAME,D1.PATH,COUNT(D2.DIRECTORY_ID) AS CHILDCOUNT FROM DIRECTORIES D1 "+
						" LEFT OUTER JOIN DIRECTORIES D2 ON D1.DIRECTORY_ID=D2.PARENT_ID "+
						" WHERE D1.MEDIA_ID=? AND D1.PARENT_ID IS NULL GROUP BY D1.DIRECTORY_ID,D1.PARENT_ID,D1.NAME,D1.PATH "+
						" ORDER BY UPPER(D1.NAME)");
				ps.setInt(1,rs.getInt("MEDIA_ID"));
				rsRoot=ps.executeQuery();
				if(rsRoot.next())
					RootDirectoryID=rsRoot.getInt(1);
					
				MediaInfo objMedia=new MediaInfo(rs.getInt("MEDIA_ID"),rs.getString("NAME"),rs.getString("PATH"),RootDirectoryID);
				DefaultMutableTreeNode objMediaNode=new DefaultMutableTreeNode(objMedia);
				
				if(rsRoot.getInt("CHILDCOUNT")>0)
				{
	        		DefaultMutableTreeNode objDummyNode=new DefaultMutableTreeNode(null);            		
	        		objMediaNode.add(objDummyNode);
				}
				
				top.add(objMediaNode);
			}
		
		}
		catch(SQLException sqle)
		{		
			SqlUtil.ReportSQLException(sqle);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			SqlUtil.CloseResultSet(rs);
			SqlUtil.CloseStatement(s);
		}
		
		ctlDirectoryTree=new JTree(top);
		ctlTreeScroll.setViewportView(ctlDirectoryTree);
		ctlDirectoryTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
	    DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
	    renderer.setLeafIcon(renderer.getOpenIcon());
	    ctlDirectoryTree.setCellRenderer(renderer);
	    
		ctlDirectoryTree.addTreeWillExpandListener(new TreeWillExpandListener() {

			@Override
			public void treeWillCollapse(TreeExpansionEvent arg0)
					throws ExpandVetoException {				
			}

			@Override
			public void treeWillExpand(TreeExpansionEvent arg0)
					throws ExpandVetoException {
				TreeWillExpand(arg0);				
			}});
		
		ctlDirectoryTree.addTreeSelectionListener(new TreeSelectionListener() {

			@Override
			public void valueChanged(TreeSelectionEvent arg0) {
				ShowFiles(arg0);				
			}
			
		});
		
    	JPopupMenu objPopupMenu=new JPopupMenu();	    
	    JMenuItem ctlDeleteMedia=new JMenuItem("delete");
	    JMenuItem ctlRepopulate= new JMenuItem("repopulate");
	    
	    objPopupMenu.add(ctlDeleteMedia);
	    objPopupMenu.add(ctlRepopulate);
	    
	    ctlDirectoryTree.setComponentPopupMenu(objPopupMenu);
	    
	    ctlDeleteMedia.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				DeleteMediaAction(arg0);
			}});
	}
	
	private void TreeWillExpand(TreeExpansionEvent e)
	{
		DefaultMutableTreeNode objTreeNode=(DefaultMutableTreeNode) e.getPath().getLastPathComponent();
		if(objTreeNode.getChildCount()>0)
		{
			DefaultMutableTreeNode objChildTreeNode=(DefaultMutableTreeNode) objTreeNode.getFirstChild();
			if(objChildTreeNode.getUserObject()==null)
			{				
				objTreeNode.removeAllChildren();
				
				ResultSet rs=null;
				PreparedStatement ps=null;
				
				try
				{
					int DirectoryID=0;
					
					if(objTreeNode.getUserObject() instanceof MediaInfo)
					{
						MediaInfo objMedia=(MediaInfo)objTreeNode.getUserObject();
						DirectoryID=objMedia.rootDirectoryID;
					}
					else
					{
						DirectoryInfo objParentDir=(DirectoryInfo)objTreeNode.getUserObject();
						DirectoryID=objParentDir.directoryID;
					}

					ps=getDBConnection().prepareStatement(
							"SELECT D1.DIRECTORY_ID,D1.PARENT_ID,D1.NAME,D1.PATH,COUNT(D2.DIRECTORY_ID) AS CHILDCOUNT FROM DIRECTORIES D1 "+
							" LEFT OUTER JOIN DIRECTORIES D2 ON D1.DIRECTORY_ID=D2.PARENT_ID "+
							" WHERE D1.PARENT_ID=? GROUP BY D1.DIRECTORY_ID,D1.PARENT_ID,D1.NAME,D1.PATH "+
							" ORDER BY UPPER(D1.NAME)");
					ps.setInt(1,DirectoryID);						
					
					rs=ps.executeQuery();
					while(rs.next())
					{
						DirectoryInfo objDirectory=new DirectoryInfo(rs.getInt("DIRECTORY_ID"),
								rs.getInt("PARENT_ID"),//rs.wasNull
								rs.getString("NAME"),rs.getString("PATH"));
						DefaultMutableTreeNode objDirectoryNode=new DefaultMutableTreeNode(objDirectory);
						
						if(rs.getInt("CHILDCOUNT")>0)
						{
			        		DefaultMutableTreeNode objDummyNode=new DefaultMutableTreeNode(null);            		
			        		objDirectoryNode.add(objDummyNode);
						}
		        		objTreeNode.add(objDirectoryNode);
					}					
				}
				catch(SQLException sqle)
				{		
					SqlUtil.ReportSQLException(sqle);
				}
				catch(Exception ex)
				{
					ex.printStackTrace();
				}
				finally
				{
					SqlUtil.CloseResultSet(rs);
					SqlUtil.ClosePreparedStatement(ps);
				}				
			}
		}
	}
	
	private void ShowFiles(TreeSelectionEvent arg0)
	{		
		ResultSet rs=null;
		PreparedStatement ps=null;
		ArrayList<FileInfo> arrFiles=new ArrayList<FileInfo>();
		
		try
		{
			int DirectoryID=0;
			DefaultMutableTreeNode objTreeNode=(DefaultMutableTreeNode) arg0.getPath().getLastPathComponent();
			
			if(objTreeNode.getUserObject() instanceof MediaInfo)
				DirectoryID=((MediaInfo)objTreeNode.getUserObject()).rootDirectoryID;
			
			if(objTreeNode.getUserObject() instanceof DirectoryInfo)
				DirectoryID=((DirectoryInfo)objTreeNode.getUserObject()).directoryID;				
				
			ps=getDBConnection().prepareStatement("SELECT FILE_ID,\"NAME\",\"EXTENSION\",\"SIZE\",\"DATECREATED\",\"COMMENT\" FROM FILES WHERE DIRECTORY_ID=? ORDER BY \"NAME\"");
			ps.setInt(1,DirectoryID);						
			
			rs=ps.executeQuery();
			while(rs.next())
			{
				arrFiles.add(new FileInfo(rs.getInt("FILE_ID"),rs.getString("NAME"),
						rs.getString("EXTENSION"),rs.getLong("SIZE"),rs.getLong("DATECREATED"),
						rs.getString("COMMENT")==null ? "" : rs.getString("COMMENT")));
			}
		}
		catch(SQLException sqle)
		{		
			SqlUtil.ReportSQLException(sqle);
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}
		finally
		{
			SqlUtil.CloseResultSet(rs);
			SqlUtil.ClosePreparedStatement(ps);
		}	
		
		if(arrFiles.size()>0)
		{
			FileListTableModel objModel=new FileListTableModel(arrFiles);
			ctlFilesList=new JTable(objModel);
			ctlFilesList.setDefaultRenderer(java.lang.Long.class,new LongValueCellRenderer());
			ctlFilesList.setDefaultRenderer(java.util.Date.class,new DateValueCellRenderer());
			ctlFilesList.setAutoCreateRowSorter(true);
			ctlListScroll.setViewportView(ctlFilesList);
		}
		else
		{
			ctlFilesList=new JTable(new DefaultTableModel());
			ctlListScroll.setViewportView(ctlFilesList);
		}
	}
	
	private void DeleteMediaAction(ActionEvent e)
	{
		DefaultMutableTreeNode objTreeNode=(DefaultMutableTreeNode) ctlDirectoryTree.getSelectionPath().getLastPathComponent();
		if(objTreeNode.getUserObject() instanceof MediaInfo)
		{
			PreparedStatement ps=null;
			
			try
			{
				ps=getDBConnection().prepareStatement("DELETE FROM MEDIA WHERE MEDIA_ID=?");
				ps.setInt(1, ((MediaInfo)objTreeNode.getUserObject()).mediaID);
				ps.execute();
				
				((DefaultTreeModel)ctlDirectoryTree.getModel()).removeNodeFromParent(objTreeNode);
			}
			catch(SQLException sqle)
			{		
				SqlUtil.ReportSQLException(sqle);
			}
			catch(Exception ex)
			{
				ex.printStackTrace();
			}
			finally
			{
				SqlUtil.ClosePreparedStatement(ps);
			}	
		}
	}
	
	public void ReloadTree()
	{
		FillCatalogData();
	}
	
	class FileListTableModel extends AbstractTableModel
	{
		private String[] _columnNames ={"Name","Extension","Size","Date created","Comment"};
		private ArrayList<FileInfo> _arrFiles=null;
		
		public FileListTableModel(ArrayList<FileInfo> arrFiles)
		{
			_arrFiles=arrFiles;
		}
		
		@Override
		public int getColumnCount() {
			return _columnNames.length;
		}

		@Override
		public int getRowCount() {
			return _arrFiles.size();
		}

		@Override
		public Object getValueAt(int arg0, int arg1) {
			FileInfo objFileInfo=_arrFiles.get(arg0);
			
			Object objRetVal=null;
			
			switch(arg1)
			{
			case 0:
				objRetVal=objFileInfo.name;
				break;
			case 1:
				objRetVal=objFileInfo.extension;
				break;
			case 2:
				objRetVal=objFileInfo.size;
				break;
			case 3:
				objRetVal=objFileInfo.getDateCreated();
				break;
			case 4:
				objRetVal=objFileInfo.comment;
				break;				
			}
			
			return objRetVal;
		}
		
		public String getColumnName(int col) {
	        return _columnNames[col];
	    }
		
	    public Class getColumnClass(int c) {   		
	        return getValueAt(0, c).getClass();
	    }
	    
	    public boolean isCellEditable(int row, int col) {
	        return col == 4;
	    }
	    
	    public void setValueAt(Object value, int row, int col) {
	    	_arrFiles.get(row).comment = value.toString();
	    	
			PreparedStatement ps=null;
			
			try
			{
				ps=getDBConnection().prepareStatement("UPDATE FILES SET COMMENT=? WHERE FILE_ID=?");
				ps.setString(1, value.toString());
				ps.setInt(2, _arrFiles.get(row).fileID);
				ps.execute();				
			}
			catch(SQLException sqle)
			{		
				SqlUtil.ReportSQLException(sqle);
			}
			catch(Exception ex)
			{
				ex.printStackTrace();
			}
			finally
			{
				SqlUtil.ClosePreparedStatement(ps);
			}	
	    	
	        fireTableCellUpdated(row, col);
	    }
	}
}
